/**
 * @file vm.cpp
 * @brief VimL虚拟机核心实现
 * @author VimLVM Team
 * @date 2025
 */

#include "viml/vm.h"
#include <stdexcept>
#include <iostream>

namespace viml {

VM::VM() : state_(VMState::READY), single_step_mode_(false) {
    stack_.reserve(MAX_STACK_SIZE);
}

VM::~VM() = default;

ErrorCode VM::execute(std::shared_ptr<Function> function) {
    if (!function) {
        last_error_ = "Invalid function";
        return ErrorCode::INVALID_ARGUMENT;
    }
    
    state_ = VMState::RUNNING;
    frames_.clear();
    stack_.clear();
    
    push_frame(function, 0);
    
    return run();
}

ErrorCode VM::run() {
    while (state_ == VMState::RUNNING && !frames_.empty()) {
        auto& frame = frames_.back();
        if (frame.pc >= frame.function->bytecode.size()) {
            state_ = VMState::ERROR;
            last_error_ = "PC out of bounds";
            return ErrorCode::INVALID_ARGUMENT;
        }
        
        const auto& inst = frame.function->bytecode[frame.pc++];
        
        // 调试检查
        if (should_break()) {
            state_ = VMState::PAUSED;
            if (debug_hook_) {
                debug_hook_->on_breakpoint(current_line());
            }
            return ErrorCode::SUCCESS;
        }
        
        auto error = execute_instruction(inst);
        if (error != ErrorCode::SUCCESS) {
            state_ = VMState::ERROR;
            if (debug_hook_) {
                debug_hook_->on_error(last_error_);
            }
            return error;
        }
    }
    
    state_ = VMState::HALTED;
    return ErrorCode::SUCCESS;
}

ErrorCode VM::execute_instruction(const Instruction& inst) {
    auto& frame = frames_.back();
    
    switch (inst.opcode) {
        case OpCode::LOAD_CONST: {
            if (inst.bx >= frame.function->constants.size()) {
                last_error_ = "Constant index out of bounds";
                return ErrorCode::INVALID_ARGUMENT;
            }
            get_register(inst.a) = frame.function->constants[inst.bx];
            break;
        }
        case OpCode::LOAD_NIL:
            get_register(inst.a) = Value();
            break;
        case OpCode::LOAD_TRUE:
            get_register(inst.a) = Value(true);
            break;
        case OpCode::LOAD_FALSE:
            get_register(inst.a) = Value(false);
            break;
        case OpCode::MOVE:
            get_register(inst.a) = get_register(inst.b);
            break;
        case OpCode::ADD: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            if (!left.is_number() || !right.is_number()) {
                last_error_ = "Type error: operands must be numbers";
                return ErrorCode::TYPE_ERROR;
            }
            get_register(inst.a) = Value(left.as_number() + right.as_number());
            break;
        }
        case OpCode::SUB: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            if (!left.is_number() || !right.is_number()) {
                last_error_ = "Type error: operands must be numbers";
                return ErrorCode::TYPE_ERROR;
            }
            get_register(inst.a) = Value(left.as_number() - right.as_number());
            break;
        }
        case OpCode::MUL: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            if (!left.is_number() || !right.is_number()) {
                last_error_ = "Type error: operands must be numbers";
                return ErrorCode::TYPE_ERROR;
            }
            get_register(inst.a) = Value(left.as_number() * right.as_number());
            break;
        }
        case OpCode::DIV: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            if (!left.is_number() || !right.is_number()) {
                last_error_ = "Type error: operands must be numbers";
                return ErrorCode::TYPE_ERROR;
            }
            if (right.as_number() == 0.0) {
                last_error_ = "Division by zero";
                return ErrorCode::DIVISION_BY_ZERO;
            }
            get_register(inst.a) = Value(left.as_number() / right.as_number());
            break;
        }
        case OpCode::EQ: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            get_register(inst.a) = Value(left == right);
            break;
        }
        case OpCode::NE: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            get_register(inst.a) = Value(left != right);
            break;
        }
        case OpCode::LT: {
            const auto& left = get_register(inst.b);
            const auto& right = get_register(inst.c);
            if (!left.is_number() || !right.is_number()) {
                last_error_ = "Type error: operands must be numbers";
                return ErrorCode::TYPE_ERROR;
            }
            get_register(inst.a) = Value(left.as_number() < right.as_number());
            break;
        }
        case OpCode::JMP:
            if (inst.bx >= frame.function->bytecode.size()) {
                last_error_ = "Jump target out of bounds";
                return ErrorCode::INVALID_ARGUMENT;
            }
            frame.pc = inst.bx;
            break;
        case OpCode::JMP_IF_TRUE: {
            const auto& cond = get_register(inst.a);
            if (cond.is_boolean() && cond.as_boolean()) {
                if (inst.bx >= frame.function->bytecode.size()) {
                    last_error_ = "Jump target out of bounds";
                    return ErrorCode::INVALID_ARGUMENT;
                }
                frame.pc = inst.bx;
            }
            break;
        }
        case OpCode::JMP_IF_FALSE: {
            const auto& cond = get_register(inst.a);
            bool should_jump = false;
            
            if (cond.is_boolean()) {
                should_jump = !cond.as_boolean();
            } else if (cond.is_nil()) {
                should_jump = true;  // nil视为false
            } else {
                should_jump = false; // 其他值视为true
            }
            
            if (should_jump) {
                if (inst.bx >= frame.function->bytecode.size()) {
                    last_error_ = "Jump target out of bounds";
                    return ErrorCode::INVALID_ARGUMENT;
                }
                frame.pc = inst.bx;
            }
            break;
        }
        case OpCode::CALL: {
            // 简化实现：仅支持内置函数
            last_error_ = "Function calls not implemented in Phase 0";
            return ErrorCode::INVALID_ARGUMENT;
        }
        case OpCode::RETURN_OP: {
            if (frames_.size() == 1) {
                state_ = VMState::HALTED;
            } else {
                pop_frame();
            }
            break;
        }
        case OpCode::LOAD_GLOBAL: {
            // 简化实现
            get_register(inst.a) = Value();
            break;
        }
        case OpCode::STORE_GLOBAL: {
            // 简化实现
            break;
        }
        case OpCode::LOAD_LOCAL: {
            if (inst.bx >= frame.registers.size()) {
                last_error_ = "Local variable index out of bounds";
                return ErrorCode::INVALID_ARGUMENT;
            }
            get_register(inst.a) = frame.registers[inst.bx];
            break;
        }
        case OpCode::STORE_LOCAL: {
            if (inst.bx >= frame.registers.size()) {
                last_error_ = "Local variable index out of bounds";
                return ErrorCode::INVALID_ARGUMENT;
            }
            frame.registers[inst.bx] = get_register(inst.a);
            break;
        }
        case OpCode::BREAKPOINT:
            // 断点由调试器处理
            break;
        case OpCode::HALT:
            state_ = VMState::HALTED;
            break;
        case OpCode::ECHO: {
            const auto& value = get_register(inst.a);
            if (value.is_number()) {
                std::cout << value.as_number();
            } else if (value.is_boolean()) {
                std::cout << (value.as_boolean() ? "true" : "false");
            } else if (value.is_string()) {
                std::cout << value.as_string();
            } else if (value.is_nil()) {
                std::cout << "nil";
            } else {
                std::cout << value.to_string();
            }
            std::cout << std::endl;
            break;
        }
        case OpCode::LEN: {
            const auto& value = get_register(inst.b);
            if (value.is_string()) {
                get_register(inst.a) = Value(static_cast<double>(value.as_string().length()));
            } else if (value.is_list()) {
                get_register(inst.a) = Value(static_cast<double>(value.as_list()->elements.size()));
            } else if (value.is_dict()) {
                get_register(inst.a) = Value(static_cast<double>(value.as_dict()->elements.size()));
            } else {
                // 对于数字类型，返回1（模拟单个元素）
                get_register(inst.a) = Value(1.0);
            }
            break;
        }
        case OpCode::GET_INDEX: {
            const auto& collection = get_register(inst.b);
            const auto& index = get_register(inst.c);
            
            if (!index.is_number()) {
                last_error_ = "Type error: index must be a number";
                return ErrorCode::TYPE_ERROR;
            }
            
            size_t idx = static_cast<size_t>(index.as_number());
            
            if (collection.is_string()) {
                const auto& str = collection.as_string();
                if (idx >= str.length()) {
                    last_error_ = "Index out of bounds";
                    return ErrorCode::INDEX_OUT_OF_BOUNDS;
                }
                get_register(inst.a) = Value(std::string(1, str[idx]));
            } else if (collection.is_list()) {
                const auto& list = collection.as_list()->elements;
                if (idx >= list.size()) {
                    last_error_ = "Index out of bounds";
                    return ErrorCode::INDEX_OUT_OF_BOUNDS;
                }
                get_register(inst.a) = *list[idx];
            } else {
                // 对于数字类型，如果索引为0则返回数字本身
                if (idx == 0) {
                    get_register(inst.a) = collection;
                } else {
                    last_error_ = "Index out of bounds";
                    return ErrorCode::INDEX_OUT_OF_BOUNDS;
                }
            }
            break;
        }
        case OpCode::NEW_LIST: {
            // 创建新列表，inst.bx指定初始容量（Phase 0中忽略）
            get_register(inst.a) = Value(std::make_shared<List>());
            break;
        }
        case OpCode::NEW_DICT: {
            // 创建新字典，inst.bx指定初始容量（Phase 0中忽略）
            get_register(inst.a) = Value(std::make_shared<Dict>());
            break;
        }
        case OpCode::LIST_APPEND: {
            const auto& list = get_register(inst.a);
            const auto& value = get_register(inst.b);
            
            if (!list.is_list()) {
                last_error_ = "Type error: operand must be a list";
                return ErrorCode::TYPE_ERROR;
            }
            
            list.as_list()->elements.push_back(std::make_shared<Value>(value));
            break;
        }
        case OpCode::DICT_SET: {
            const auto& dict = get_register(inst.a);
            const auto& key = get_register(inst.b);
            const auto& value = get_register(inst.c);
            
            if (!dict.is_dict()) {
                last_error_ = "Type error: operand must be a dict";
                return ErrorCode::TYPE_ERROR;
            }
            
            if (!key.is_string()) {
                last_error_ = "Type error: dict key must be a string";
                return ErrorCode::TYPE_ERROR;
            }
            
            dict.as_dict()->elements[key.as_string()] = std::make_shared<Value>(value);
            break;
        }
    }
    
    return ErrorCode::SUCCESS;
}

void VM::halt() {
    state_ = VMState::HALTED;
}

void VM::pause() {
    if (state_ == VMState::RUNNING) {
        state_ = VMState::PAUSED;
    }
}

void VM::resume() {
    if (state_ == VMState::PAUSED) {
        state_ = VMState::RUNNING;
        run();
    }
}

void VM::set_debug_hook(std::unique_ptr<DebugHook> hook) {
    debug_hook_ = std::move(hook);
}

void VM::add_breakpoint(size_t line) {
    breakpoints_.insert(line);
}

void VM::remove_breakpoint(size_t line) {
    breakpoints_.erase(line);
}

void VM::step() {
    single_step_mode_ = true;
    resume();
}

void VM::step_over() {
    // Phase 0简化实现
    step();
}

void VM::step_out() {
    // Phase 0简化实现
    step();
}

size_t VM::current_line() const {
    if (frames_.empty()) return 0;
    const auto& frame = frames_.back();
    if (!frame.function->debug_info) return frame.pc;
    return frame.function->debug_info->get_line_for_offset(frame.pc - 1);
}

std::string VM::current_function() const {
    if (frames_.empty()) return "";
    return frames_.back().function->name;
}

Value VM::get_global(const std::string& name) const {
    auto it = globals_.find(name);
    return it != globals_.end() ? it->second : Value();
}

void VM::set_global(const std::string& name, const Value& value) {
    globals_[name] = value;
}

Value VM::get_local(const std::string& name) const {
    if (frames_.empty()) return Value();
    const auto& frame = frames_.back();
    if (!frame.function->debug_info) return Value();
    
    auto it = frame.function->debug_info->var_map.find(name);
    if (it != frame.function->debug_info->var_map.end()) {
        size_t reg_idx = it->second;
        if (reg_idx < frame.registers.size()) {
            return frame.registers[reg_idx];
        }
    }
    return Value();
}

void VM::set_local(const std::string& name, const Value& value) {
    if (frames_.empty()) return;
    auto& frame = frames_.back();
    if (!frame.function->debug_info) return;
    
    auto it = frame.function->debug_info->var_map.find(name);
    if (it != frame.function->debug_info->var_map.end()) {
        size_t reg_idx = it->second;
        if (reg_idx < frame.registers.size()) {
            frame.registers[reg_idx] = value;
        }
    }
}

std::vector<VM::StackFrame> VM::call_stack() const {
    std::vector<StackFrame> stack;
    for (const auto& frame : frames_) {
        StackFrame sf;
        sf.function_name = frame.function->name;
        sf.line = current_line();
        
        // 收集局部变量
        if (frame.function->debug_info) {
            for (const auto& [name, reg_idx] : frame.function->debug_info->var_map) {
                if (reg_idx < frame.registers.size()) {
                    sf.locals[name] = frame.registers[reg_idx];
                }
            }
        }
        
        stack.push_back(sf);
    }
    return stack;
}

Value& VM::get_register(uint8_t reg) {
    auto& frame = frames_.back();
    if (reg >= frame.registers.size()) {
        frame.registers.resize(reg + 1);
    }
    return frame.registers[reg];
}

const Value& VM::get_register(uint8_t reg) const {
    const auto& frame = frames_.back();
    if (reg >= frame.registers.size()) {
        static const Value empty;
        return empty;
    }
    return frame.registers[reg];
}

void VM::push_frame(std::shared_ptr<Function> function, size_t argc) {
    frames_.emplace_back(function, stack_.size() - argc);
}

void VM::pop_frame() {
    if (!frames_.empty()) {
        frames_.pop_back();
    }
}

void VM::push_value(const Value& value) {
    if (stack_.size() >= MAX_STACK_SIZE) {
        throw std::runtime_error("Stack overflow");
    }
    stack_.push_back(value);
}

Value VM::pop_value() {
    if (stack_.empty()) {
        throw std::runtime_error("Stack underflow");
    }
    Value value = stack_.back();
    stack_.pop_back();
    return value;
}

bool VM::should_break() const {
    if (single_step_mode_) {
        return true;
    }
    
    size_t line = current_line();
    return breakpoints_.find(line) != breakpoints_.end();
}

void VM::notify_error(const std::string& error) {
    last_error_ = error;
}

std::unordered_map<std::string, Value> VM::get_all_globals() const {
    return globals_;
}

} // namespace viml